const { existsSync, createWriteStream } = require('fs')
const { exec } = require('child_process')
const path = require('path')
const { readdir, statSync } = require('fs')
const https = require('https')

const nativeId = utools.getNativeId() + '_'
function getConfig(name) {
	return utools.dbStorage.getItem(nativeId + name)
}
function setConfig(name, value) {
	utools.dbStorage.setItem(nativeId + name, value)
}

let cmdFile = getConfig('file_path')
let analysError = 0
let result = []
const onEnter = async (action, callbackSetList) => {
	//判断文件是否存在
	if (cmdFile === null || !existsSync(cmdFile)) {
		callbackSetList([
			{
				title: '尚未配置 handle 文件路径,点击下载 handle',
				description: '选择路径,自动下载 handle.exe',
				icon: '/imgs/down.png',
				down: true,
			},
			{
				title: '选择 handle.exe 路径',
				description: '我已下载 handle.exe,手动选择路径',
				icon: '/imgs/select.png',
				select: true,
			},
			{
				title: '了解 handle.exe',
				description: '点解打开 handle.exe 页面,可手动下载 handle.exe',
				icon: '/imgs/browser.png',
				url: 'https://learn.microsoft.com/zh-CN/sysinternals/downloads/handle',
			},
		])
		return
	}
	callbackSetList([{ title: '正在分析中...', description: '请稍等' }])
	result = await analysis(action.payload)
	if (result.length === 0) {
		callbackSetList([
			{
				title: '查询成功',
				description: '没有发现文件被占用',
			},
		])
		return
	}
	callbackSetList(result)
}
/**
 * 分析文件或文件夹列表
 * @return {Array} 返回分析结果
 */
async function analysis(files) {
	const resultTemp = []
	for (let index = 0; index < files.length; index++) {
		const item = files[index]
		if (item.isDirectory) {
			resultTemp.push(...(await analysiDir(item.path)))
		} else {
			try {
				resultTemp.push(...(await analysiFile(item.path)))
			} catch (e) {
				analysError++
			}
		}
	}
	if (analysError > 0) {
		resultTemp.splice(0, 0, {
			title: '未能全部分析成功',
			description: `${analysError}个文件分析失败了`,
		})
	}
	return resultTemp
}
function analysiDir(dirpath) {
	//获取文件夹中的所有文件
	return new Promise((resolve, reject) => {
		readdir(dirpath, async function (err, files) {
			if (err) {
				console.error(err)
				reject(err)
				return
			}
			const resultTemp = []
			for (let index = 0; index < files.length; index++) {
				const item = files[index]
				const fullpath = path.join(dirpath, item)
				const isDirectory = statSync(fullpath).isDirectory()
				//如果是文件夹,递归
				if (isDirectory) {
					resultTemp.push(...(await analysiDir(fullpath)))
				}
				try {
					resultTemp.push(...(await analysiFile(fullpath)))
				} catch (e) {
					analysError++
				}
			}
			resolve(resultTemp)
		})
	})
}
function analysiFile(filepath) {
	return new Promise((resolve, reject) => {
		const cmd = `"${cmdFile}" /nobanner "${filepath}"`
		exec(cmd, function (error, stdout) {
			if (error) {
				console.error(error)
				reject(error)
				return
			}
			//No matching handles found.
			if (stdout.includes('No matching handles found.')) {
				resolve([])
				return
			}
			//有占用
			const list = stdout.split('\n').filter((item) => item !== '')
			let resultTemp = list.map((item) => {
				const arr = item.split(/\s+/)
				const pid = arr[2]
				const title = `占用进程：${arr[0]}  PID：${pid}`
				const description = '占用文件：' + filepath
				return {
					title,
					description,
					pid,
				}
			})
			//去掉重复pid
			resultTemp = resultTemp.filter((item, index, arr) => {
				return arr.findIndex((item2) => item2.pid === item.pid) === index && !item.title.endsWith('explorer.exe')
			})
			resolve(resultTemp)
		})
	})
}
window.exports = {
	analysis: {
		mode: 'list', // 列表模式
		args: {
			// 进入插件应用时调用（可选）
			enter: onEnter,
			// 子输入框内容变化时被调用 可选 (未设置则无搜索)
			search: (action, searchWord, callbackSetList) => {
				if (!result) return
				const list = result.filter((item) => item.title.includes(searchWord) || item.description.includes(searchWord))
				callbackSetList(list)
			},
			// 用户选择列表中某个条目时被调用
			select: (action, itemData, callbackSetList) => {
				window.utools.hideMainWindow()
				if (itemData.pid) {
					const cmd = `taskkill /pid ${itemData.pid} /f`
					exec(cmd, function (error, stdout) {
						if (error) {
							window.utools.showNotification('结束进程失败')
							console.log(error)
							return
						}
						window.utools.showNotification('结束进程成功')
						onEnter(action, callbackSetList)
					})
					return
				}
				if (itemData.url) {
					utools.shellOpenExternal(itemData.url)
					utools.outPlugin()
					return
				}
				if (itemData.down) {
					//下载 handle.exe
					const handlePath = utools.showSaveDialog({
						title: '保存 handle.exe(不要存放在C盘)',
						defaultPath: path.join(utools.getPath('downloads'), 'handle.exe'),
						filters: [{ name: 'handle.exe', extensions: ['exe'] }],
					})
					if (!handlePath) {
						window.utools.showNotification('取消下载')
						window.utools.outPlugin()
						return
					}
					const url = 'https://live.sysinternals.com/handle.exe'
					const file = createWriteStream(handlePath)
					const request = https.get(url, function (response) {
						response.pipe(file)
						file.on('finish', function () {
							file.close()
							cmdFile = handlePath
							setConfig('file_path', handlePath)
							window.utools.showNotification('handle.exe 下载成功')
							onEnter(action, callbackSetList)
						})
						file.on('error', function (err) {
							window.utools.showNotification('handle.exe 下载失败')
							window.utools.outPlugin()
						})
					})
					return
				}
				if (itemData.select) {
					//选择文件
					const res = utools.showOpenDialog({
						title: '选择 handle.exe 路径(不要存放在C盘)',
						properties: ['openFile'],
						filters: [{ name: 'handle.exe', extensions: ['exe'] }],
					})
					if (res) {
						cmdFile = res[0]
						setConfig('file_path', cmdFile)
						window.utools.showNotification('handle.exe 路径设置成功')
						onEnter(action, callbackSetList)
					}
				}
			},
			// 子输入框为空时的占位符，默认为字符串"搜索"
			placeholder: '搜索进程或文件,点击列表关闭进程',
		},
	},
}
